import json
import os
from PySide6.QtWidgets import QWidget, QMessageBox, QDialog
from PySide6.QtCore import Signal, QObject

from components import ButtonComponent, TextDisplayComponent, SliderComponent
from components.property_editor import PropertyEditDialog

class ProtocolManager(QObject):
    """协议管理器类，负责加载、解析协议配置文件，以及创建和管理UI组件"""
    
    # 自定义信号
    component_action = Signal(str, str, object)  # 组件ID，操作类型，数据
    
    def __init__(self):
        super().__init__()
        self.current_protocol = None
        self.protocol_file = None
        self.components = {}  # 组件ID -> 组件实例
    
    def load_protocol(self, protocol_file, container):
        """加载协议配置文件并创建UI组件"""
        try:
            self.protocol_file = protocol_file
            
            # 清除现有组件
            self.clear_components()
            
            # 读取协议配置文件
            with open(protocol_file, 'r', encoding='utf-8') as f:
                self.current_protocol = json.load(f)
            
            # 创建UI组件
            if 'components' in self.current_protocol:
                for comp_config in self.current_protocol['components']:
                    component = self.create_component(comp_config, container)
                    if component:
                        self.components[comp_config['id']] = component
                        
                        # 设置组件位置
                        if 'position' in comp_config:
                            pos = comp_config['position']
                            component.move(pos['x'], pos['y'])
                        
                        # 设置组件大小
                        if 'size' in comp_config:
                            size = comp_config['size']
                            component.resize(size['width'], size['height'])
                        
                        # 设置锁定状态
                        if 'locked' in comp_config:
                            component.set_locked(comp_config['locked'])
                        
                        # 连接信号 - 修复：将信号连接移到循环内部
                        component.position_changed.connect(self.on_component_position_changed)
                        component.lock_changed.connect(self.on_component_lock_changed)
                        component.delete_requested.connect(self.on_component_delete_requested)
                        # 添加属性编辑信号连接
                        component.property_edit_requested.connect(self.on_component_property_edit_requested)
                        
                        # 根据组件类型连接特定信号
                        if isinstance(component, ButtonComponent):
                            print(f"连接按钮 {comp_config['id']} 的点击信号")
                            component.button_clicked.connect(self.on_button_clicked)
                        elif isinstance(component, SliderComponent):
                            print(f"连接滑动条 {comp_config['id']} 的值改变信号")
                            component.slider_value_changed.connect(self.on_slider_value_changed)
                        
                        # 显示组件
                        component.show()
            
            return True
        except Exception as e:
            QMessageBox.critical(None, "错误", f"加载协议配置文件失败: {str(e)}")
            print(f"加载协议配置文件异常: {str(e)}")
            import traceback
            print(traceback.format_exc())
            return False
    
    def create_component(self, comp_config, parent):
        """根据配置创建UI组件"""
        comp_type = comp_config.get('type', '')
        comp_id = comp_config.get('id', '')
        
        if not comp_id:
            return None
        
        if comp_type == 'button':
            text = comp_config.get('text', '按钮')
            # 创建按钮组件并设置文本
            button_comp = ButtonComponent(comp_id, text, parent)
            # 确保标题完整显示
            button_comp.title_label.setText(f"按钮: {comp_id}")
            button_comp.title_label.setMinimumWidth(max(150, 10 * len(f"按钮: {comp_id}")))
            button_comp.button.setText(text)
            return button_comp
            
        elif comp_type == 'text_display':
            text = comp_config.get('text', '')
            # 创建文本显示组件并设置文本
            text_comp = TextDisplayComponent(comp_id, text, parent)
            # 确保标题完整显示
            text_comp.title_label.setText(f"文本显示: {comp_id}")
            text_comp.title_label.setMinimumWidth(max(150, 10 * len(f"文本显示: {comp_id}")))
            text_comp.text_display.setText(text)
            return text_comp
            
        elif comp_type == 'slider':
            label = comp_config.get('label', '滑动条')
            min_val = comp_config.get('min', 0)
            max_val = comp_config.get('max', 100)
            default_val = comp_config.get('default', 50)
            unit = comp_config.get('unit', '')  # 获取单位信息
            # 创建滑动条组件并设置参数
            slider_comp = SliderComponent(comp_id, label, min_val, max_val, default_val, unit, parent)
            # 确保标题完整显示
            slider_comp.title_label.setText(f"滑动条: {comp_id}")
            slider_comp.title_label.setMinimumWidth(max(150, 10 * len(f"滑动条: {comp_id}")))
            # 确保标签完整显示
            slider_comp.label.setText(label)
            slider_comp.label.setMinimumWidth(max(200, 10 * len(label)))
            slider_comp.unit = unit
            # 更新值显示
            value = slider_comp.get_value()
            value_text = f"{value}{' ' + unit if unit else ''}"
            slider_comp.value_label.setText(value_text)
            return slider_comp
        
        return None
    
    def clear_components(self):
        """清除所有组件"""
        for component in self.components.values():
            component.deleteLater()
        self.components.clear()
    
    def save_protocol(self):
        """保存协议配置到文件"""
        if not self.current_protocol or not self.protocol_file:
            return False
        
        try:
            # 更新组件配置
            for comp_id, component in self.components.items():
                # 查找对应的组件配置
                for comp_config in self.current_protocol['components']:
                    if comp_config['id'] == comp_id:
                        # 更新位置
                        comp_config['position'] = {
                            'x': component.pos().x(),
                            'y': component.pos().y()
                        }
                        # 更新大小
                        comp_config['size'] = {
                            'width': component.width(),
                            'height': component.height()
                        }
                        # 更新锁定状态
                        comp_config['locked'] = component.locked
                        break
            
            # 写入文件
            with open(self.protocol_file, 'w', encoding='utf-8') as f:
                json.dump(self.current_protocol, f, indent=2, ensure_ascii=False)
            
            return True
        except Exception as e:
            QMessageBox.critical(None, "错误", f"保存协议配置文件失败: {str(e)}")
            return False
    
    def create_new_protocol(self, protocol_name, file_path):
        """创建新的协议配置文件"""
        try:
            # 创建基本结构
            new_protocol = {
                "protocol_name": protocol_name,
                "description": "新建协议",
                "version": "1.0",
                "components": []
            }
            
            # 写入文件
            with open(file_path, 'w', encoding='utf-8') as f:
                json.dump(new_protocol, f, indent=2, ensure_ascii=False)
            
            return True
        except Exception as e:
            QMessageBox.critical(None, "错误", f"创建协议配置文件失败: {str(e)}")
            return False
    
    def add_component(self, comp_type, comp_id, container, pos=None, comp_info=None):
        """添加新组件"""
        if comp_id in self.components:
            # ID已存在
            QMessageBox.warning(None, "警告", f"组件ID '{comp_id}' 已存在")
            return None
        
        # 创建组件配置
        comp_config = {
            "id": comp_id,
            "type": comp_type
        }
        
        # 如果提供了组件信息，优先使用提供的信息
        if comp_info:
            for key, value in comp_info.items():
                if key != "id" and key != "type":  # 这两个已经设置了
                    comp_config[key] = value
        else:
            # 根据类型添加默认属性
            if comp_type == 'button':
                comp_config["text"] = "新按钮"
            elif comp_type == 'text_display':
                comp_config["text"] = "文本显示"
            elif comp_type == 'slider':
                comp_config["label"] = "参数调节"
                comp_config["min"] = 0
                comp_config["max"] = 100
                comp_config["default"] = 50
                comp_config["unit"] = ""  # 添加默认空单位
        
        # 创建组件
        component = self.create_component(comp_config, container)
        if component:
            # 设置位置
            if pos:
                component.move(pos.x(), pos.y())
                comp_config["position"] = {"x": pos.x(), "y": pos.y()}
            else:
                # 默认位置
                component.move(50, 50)
                comp_config["position"] = {"x": 50, "y": 50}
            
            # 设置默认大小
            if comp_type == 'button':
                component.resize(220, 150)
                comp_config["size"] = {"width": 220, "height": 150}
            elif comp_type == 'text_display':
                component.resize(320, 250)
                comp_config["size"] = {"width": 320, "height": 250}
            elif comp_type == 'slider':
                component.resize(400, 180)
                comp_config["size"] = {"width": 400, "height": 180}
            
            # 默认不锁定
            component.set_locked(False)
            comp_config["locked"] = False
            
            # 连接信号
            component.position_changed.connect(self.on_component_position_changed)
            component.lock_changed.connect(self.on_component_lock_changed)
            component.delete_requested.connect(self.on_component_delete_requested)
            # 添加属性编辑信号连接
            component.property_edit_requested.connect(self.on_component_property_edit_requested)
            
            # 根据组件类型连接特定信号
            if isinstance(component, ButtonComponent):
                print(f"连接新添加的按钮 {comp_id} 的点击信号")
                component.button_clicked.connect(self.on_button_clicked)
            elif isinstance(component, SliderComponent):
                print(f"连接新添加的滑动条 {comp_id} 的值改变信号")
                component.slider_value_changed.connect(self.on_slider_value_changed)
            
            # 保存组件
            self.components[comp_id] = component
            
            # 更新协议配置
            if self.current_protocol:
                self.current_protocol['components'].append(comp_config)
            
            # 显示组件
            component.show()
            
            return component
        
        return None
    
    def remove_component(self, comp_id):
        """移除组件"""
        if comp_id in self.components:
            # 移除组件实例
            component = self.components.pop(comp_id)
            component.deleteLater()
            
            # 更新协议配置
            if self.current_protocol:
                self.current_protocol['components'] = [
                    comp for comp in self.current_protocol['components'] 
                    if comp['id'] != comp_id
                ]
            
            return True
        
        return False
    
    # 信号处理函数
    def on_component_position_changed(self, comp_id, x, y):
        """处理组件位置改变"""
        # 如果需要实时保存，可以在这里调用save_protocol
        pass
    
    def on_component_lock_changed(self, comp_id, locked):
        """处理组件锁定状态改变"""
        # 自动保存锁定状态到配置
        if self.current_protocol:
            for comp_config in self.current_protocol['components']:
                if comp_config['id'] == comp_id:
                    comp_config['locked'] = locked
                    break
            
            # 保存配置
            self.save_protocol()
    
    def on_button_clicked(self, comp_id):
        """处理按钮点击"""
        print(f"ProtocolManager.on_button_clicked: 按钮 {comp_id} 被点击")
        # 查找对应的按钮配置
        if self.current_protocol:
            for comp_config in self.current_protocol['components']:
                if comp_config['id'] == comp_id and comp_config['type'] == 'button':
                    if 'action' in comp_config:
                        action = comp_config['action']
                        print(f"找到按钮 {comp_id} 的动作配置: {action}")
                        # 发射操作信号
                        self.component_action.emit(comp_id, 'button_click', action)
                        print(f"已发射组件操作信号: {comp_id}, button_click, {action}")
                    else:
                        print(f"警告: 按钮 {comp_id} 没有配置动作")
                    break
            else:
                print(f"错误: 找不到按钮 {comp_id} 的配置")
    
    def on_slider_value_changed(self, comp_id, value):
        """处理滑动条值改变"""
        print(f"ProtocolManager.on_slider_value_changed: 滑动条 {comp_id} 值改变为 {value}")
        # 查找对应的滑动条配置
        if self.current_protocol:
            for comp_config in self.current_protocol['components']:
                if comp_config['id'] == comp_id and comp_config['type'] == 'slider':
                    if 'action' in comp_config:
                        action = comp_config['action']
                        print(f"找到滑动条 {comp_id} 的动作配置: {action}")
                        # 格式化数据模板
                        if 'data_template' in action:
                            try:
                                data = action['data_template'].format(value=value)
                                print(f"格式化数据模板成功: {data}")
                                action['data'] = data
                            except Exception as e:
                                print(f"格式化数据模板失败: {str(e)}")
                        else:
                            print(f"警告: 滑动条 {comp_id} 没有数据模板")
                        
                        # 发射操作信号
                        self.component_action.emit(comp_id, 'slider_change', action)
                        print(f"已发射组件操作信号: {comp_id}, slider_change, {action}")
                    else:
                        print(f"警告: 滑动条 {comp_id} 没有配置动作")
                    break
            else:
                print(f"错误: 找不到滑动条 {comp_id} 的配置")
    
    def on_component_delete_requested(self, comp_id):
        """处理组件删除请求"""
        # 确认删除
        reply = QMessageBox.question(
            None, 
            "确认删除", 
            f"确定要删除组件 {comp_id} 吗？",
            QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, 
            QMessageBox.StandardButton.No
        )
        
        if reply == QMessageBox.StandardButton.Yes:
            # 执行删除
            self.remove_component(comp_id)
            # 保存协议配置
            self.save_protocol()
    
    def on_component_property_edit_requested(self, comp_id):
        """处理组件属性编辑请求"""
        print(f"处理组件 {comp_id} 的属性编辑请求")
        
        # 查找组件及其配置
        if comp_id in self.components and self.current_protocol:
            component = self.components[comp_id]
            comp_config = None
            
            # 查找对应的组件配置
            for config in self.current_protocol['components']:
                if config['id'] == comp_id:
                    comp_config = config
                    break
            
            if comp_config:
                # 确定组件类型
                comp_type = comp_config['type']
                
                # 创建属性编辑对话框
                dialog = PropertyEditDialog(comp_type, comp_id, comp_config)
                
                # 显示对话框
                if dialog.exec() == QDialog.DialogCode.Accepted:
                    # 获取更新后的配置
                    updated_config = dialog.get_updated_config()
                    
                    # 更新组件
                    self._update_component_from_config(component, updated_config)
                    
                    # 更新协议配置
                    for i, config in enumerate(self.current_protocol['components']):
                        if config['id'] == comp_id:
                            self.current_protocol['components'][i] = updated_config
                            break
                    
                    # 保存协议配置
                    self.save_protocol()
                    print(f"组件 {comp_id} 的属性已更新")
    
    def _update_component_from_config(self, component, config):
        """根据配置更新组件"""
        comp_type = config['type']
        
        # 根据组件类型更新属性
        if comp_type == 'button' and isinstance(component, ButtonComponent):
            # 更新按钮文本
            if 'text' in config:
                component.button.setText(config['text'])
        
        elif comp_type == 'text_display' and isinstance(component, TextDisplayComponent):
            # 更新文本内容
            if 'text' in config:
                component.set_text(config['text'])
        
        elif comp_type == 'slider' and isinstance(component, SliderComponent):
            # 更新滑动条标签
            if 'label' in config:
                component.label.setText(config['label'])
            
            # 更新滑动条范围和当前值
            if 'min' in config and 'max' in config:
                component.slider.setMinimum(config['min'])
                component.slider.setMaximum(config['max'])
                
                # 确保当前值在新范围内
                current_value = component.slider.value()
                if current_value < config['min']:
                    component.set_value(config['min'])
                elif current_value > config['max']:
                    component.set_value(config['max'])
            
            # 更新单位
            if 'unit' in config:
                component.unit = config['unit']
                value = component.get_value()
                value_text = f"{value}{' ' + config['unit'] if config['unit'] else ''}"
                component.value_label.setText(value_text)
    
    def update_text_display(self, char_uuid, value):
        """更新文本显示组件"""
        if self.current_protocol:
            for comp_config in self.current_protocol['components']:
                if comp_config['type'] == 'text_display' and 'binding' in comp_config:
                    binding = comp_config['binding']
                    if binding.get('characteristic') == char_uuid:
                        comp_id = comp_config['id']
                        if comp_id in self.components:
                            component = self.components[comp_id]
                            if isinstance(component, TextDisplayComponent):
                                # 根据格式转换值
                                if binding.get('format') == 'hex':
                                    text = value.hex(' ')
                                else:
                                    try:
                                        text = value.decode('utf-8')
                                    except UnicodeDecodeError:
                                        text = f"[Invalid ASCII]: {value.hex(' ')}"
                                
                                # 设置文本
                                component.set_text(text) 